/*
  stm32flash - Open Source ST STM32 flash program for *nix
  Copyright 2010 Geoffrey McRae <geoff@spacevs.com>
  Copyright 2011 Steve Markgraf <steve@steve-m.de>
  Copyright 2012 Tormod Volden <debian.tormod@gmail.com>
  Copyright 2013 Antonio Borneo <borneo.antonio@gmail.com>

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 2
  of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
  USA.
*/


#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "init.h"
#include "parsers/parser.h"
#include "port.h"
#include "serial.h"
#include "stm32.h"
#include "utils.h"
#include "parsers/binary.h"
#include "parsers/hex.h"
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "printl.h"
#include <termios.h>
#include "cJSON.h"


#define ERR_FLAG "ER"

int                    input_number(char *prompt);
void                   test_rw(struct port_interface *port, char *pro_cmd, char *ret_out, int len, int show);
void                   float2str(float data, char *out, int len);
struct port_interface *g_port;
int                    g_dbgfd;
struct olp
{
    int r1_on, r2_on, tx_on;  // 相当与在主路还是在备路
    int route_bak;
    // float rx_p;
    float r1_p;
    float r2_p;
    float tx_p;
    float r1_s, r2_s, tx_s;
    int   sw_auto_sec;
    int   sw_manual_sec;


#define WAVE_1310 0
#define WAVE_1550 1
    int r1_w, r2_w, tx_w;  // 波长

#define OLP_MODE_AUTO 0
#define OLP_MODE_MANUAL 1
    int mode;
};


struct this_dlg
{
    struct port_interface *port;
    struct olp             m_olp;
    int                    fource;
    pthread_cond_t         cond;
    pthread_mutex_t        mutex;
    bool                   en_draw;
};


#define VERSION "0.4"

/* device globals */
stm32_t *stm = NULL;

void     *p_st   = NULL;
parser_t *parser = NULL;

/* settings */
struct port_options port_opts = {
    .device = NULL,
    .device = "/dev/ttymxc4",
    // .baudRate		= SERIAL_BAUD_57600,
    .baudRate    = SERIAL_BAUD_115200,
    .serial_mode = "8e1",
    // .serial_mode		= "8n1",
    .bus_addr     = 0,
    .rx_frame_max = STM32_MAX_RX_FRAME,
    .tx_frame_max = STM32_MAX_TX_FRAME,
};
int      rd           = 0;
int      wr           = 0;
int      wu           = 0;
int      rp           = 0;
int      ur           = 0;
int      eraseOnly    = 0;
int      crc          = 0;
int      npages       = 0;
int      spage        = 0;
int      no_erase     = 0;
char     verify       = 0;
int      retry        = 10;
char     exec_flag    = 0;
uint32_t execute      = 0;
char     init_flag    = 1;
char     force_binary = 0;
char     reset_flag   = 0;
char    *filename;
char    *gpio_seq      = NULL;
uint32_t start_addr    = 0;
uint32_t readwrite_len = 0;

/* functions */
int  parse_options(int argc, char *argv[]);
void show_help(char *name);

static int is_addr_in_ram(uint32_t addr)
{
    return addr >= stm->dev->ram_start && addr < stm->dev->ram_end;
}

static int is_addr_in_flash(uint32_t addr)
{
    return addr >= stm->dev->fl_start && addr < stm->dev->fl_end;
}

static int flash_addr_to_page_floor(uint32_t addr)
{
    if (!is_addr_in_flash(addr))
        return 0;

    return (addr - stm->dev->fl_start) / stm->dev->fl_ps;
}

static int flash_addr_to_page_ceil(uint32_t addr)
{
    if (!(addr >= stm->dev->fl_start && addr <= stm->dev->fl_end))
        return 0;

    return (addr + stm->dev->fl_ps - 1 - stm->dev->fl_start) / stm->dev->fl_ps;
}

static uint32_t flash_page_to_addr(int page)
{
    return stm->dev->fl_start + page * stm->dev->fl_ps;
}


void test_rw(struct port_interface *port, char *pro_cmd, char *ret_out, int len, int show)
{
    char *cmd = pro_cmd;
    char  strout[128];
    int   ret;

    pthread_mutex_lock(&port->mutex);
    port->write(port, cmd, strlen(cmd));
    sleep(2);  // 至少延迟800ms
    memset(strout, 0, len);
    ret = port->read(port, strout, sizeof(strout));
    pthread_mutex_unlock(&port->mutex);

    if (show) {
        printf("out: %s;\r\n\tin: %s\r\n", pro_cmd, strout);
    }
    strncpy(ret_out, strout, len);
}


struct olp g_param;

void float2str(float data, char *out, int len)
{
    float pre  = data;
    char  flag = '+';

    if (data < 0) {
        pre  = 0 - data;
        flag = '-';
    }
    snprintf(out, len, "%c%05.2f", flag, pre);
    return;
}


/*
 * 初始化指针，防止splitString 返回NULL
 * INIT_LIST(ptr, 20);
 * printf("[0] %s\r\n", ptr[0]);
 * printf("[1] %s\r\n", ptr[1]);
 */
#define INIT_LIST(ptr, length)             \
    char *ptr[length];                     \
    do {                                   \
        for (int i = 0; i < length; i++) { \
            ptr[i] = "None";               \
        }                                  \
    } while (0)

/*
 * 使用后必须splitFree(ptr, count)
 */
// 以后可能更换成不需要malloc的版本，tokens指向str的内容，str的delimiters改成'\0'
int splitString(const char *str, const char *delimiters, char **tokens, int maxTokens)
{
    char *token;
    int   count = 0;

    // 复制字符串以便修改
    char *strCopy = strdup(str);
    if (strCopy == NULL) {
        return -1;  // 内存分配失败
    }

    // 使用 strtok 函数分割字符串
    token = strtok(strCopy, delimiters);
    while (token != NULL && count < maxTokens) {
        tokens[count] = strdup(token);
        if (tokens[count] == NULL) {
            // 内存分配失败，释放已分配的内存
            for (int i = 0; i < count; i++) {
                free(tokens[i]);
            }
            free(strCopy);
            return -1;
        }
        count++;
        token = strtok(NULL, delimiters);
    }

    free(strCopy);

    return count;
}

void splitFree(char **tokens, int count)
{
    for (int i = 0; i < count; i++) {
        free(tokens[i]);
    }
}


#define ENABLE_SHOW (1)
#define DISABLE_SHOW (0)

void get_info_query(struct port_interface *port, struct olp *dev_olp)
{
    char  strout[128];
    int   d1, d2, d3;
    float f1, f2, f3;

#if 0
    char *ptr[20];
    for (int i = 0; i < 20; i++) {
        ptr[i] = "None";
    }
#else
    INIT_LIST(ptr, 20);
#endif
    int maxTokens = sizeof(ptr) / sizeof(ptr[0]);
    int count;
    dev_olp->sw_auto_sec = 44;
    // test_rw(port, "<AD01_1_B_?>", strout, sizeof(strout), !DISABLE_SHOW);
    test_rw(port, "<AD01_1_QUERY>", strout, sizeof(strout), DISABLE_SHOW);
    dprintf(g_dbgfd, "out: %s;\r\n\tin: %s\r\n", "<AD01_1_QUERY>", strout);
    // printf("%s %d\r\n", __FUNCTION__, __LINE__);
    // test_rw(port, "<AD17_1_QUERY>", strout, sizeof(strout), !DISABLE_SHOW);

    // TODO 字符串非法检测
    strout[strlen(strout) - 1] = '\0';

    count = splitString(strout, "_", ptr, maxTokens);

    dev_olp->r1_p = atof(ptr[2]);
    dev_olp->r1_s = atof(ptr[3]);

    dev_olp->r2_p = atof(ptr[4]);
    dev_olp->r2_s = atof(ptr[5]);

    dev_olp->tx_p = atof(ptr[6]);
    dev_olp->tx_s = atof(ptr[7]);

    dev_olp->r1_w = atof(ptr[8]);
    dev_olp->r2_w = atof(ptr[9]);
    dev_olp->tx_w = atof(ptr[10]);

    if (atoi(ptr[11]) == 1) {
        dev_olp->mode = OLP_MODE_AUTO;
    }
    else {
        dev_olp->mode = OLP_MODE_MANUAL;
    }

    dev_olp->route_bak     = atof(ptr[12]);
    dev_olp->sw_auto_sec   = atof(ptr[13]) * 60 + atof(ptr[14]);
    dev_olp->sw_manual_sec = atof(ptr[15]) * 60;
    // printf("dev_olp->sw_manual_sec %d %s\r\n", dev_olp->sw_manual_sec, ptr[15]);

    splitFree(ptr, count);
}

void get_info(void *port)
{
    char  strout[128];
    int   d1, d2, d3;
    float f1, f2, f3;
    char *ptr[10];
    int   maxTokens = sizeof(ptr) / sizeof(ptr[0]);
    int   count;

    test_rw(port, "<AD01_1_B_?>", strout, sizeof(strout), ENABLE_SHOW);
    strout[strlen(strout) - 1] = '\0';
    count                      = splitString(strout, "_", ptr, maxTokens);
    if (count >= 0) {
        for (int i = 0; i < count; i++) {
            printf("%s\n", ptr[i]);
            //   free(ptr[i]); // 释放内存
        }
    }
    else {
        printf("Error splitting string.\n");
    }

    printf("pow %f\r\n", ptr[2]);
    g_param.r1_on = atof(ptr[2]);
    g_param.r2_on = atof(ptr[3]);
    g_param.tx_p  = atof(ptr[4]);
    g_param.r1_p  = atof(ptr[2]);
    g_param.r2_p  = atof(ptr[3]);
    if (atoi(ptr[5]) == 1) {
        g_param.mode = OLP_MODE_AUTO;
    }
    else {
        g_param.mode = OLP_MODE_MANUAL;
    }
}


// #define GUI_ID_MODE (0)
// #define GUI_ID_R1_S (1)
// #define GUI_ID_R2_S (2)
// #define GUI_ID_TX_S (3)
typedef enum {
    E_GUI_ID_MODE = 0,
    E_GUI_ID_MS,  // 主和从路切换
    E_GUI_ID_AUTO,
    E_GUI_ID_MANUAL,
    E_GUI_ID_R1_S,
    E_GUI_ID_R2_S,
    E_GUI_ID_TX_S,
    E_GUI_ID_R1_W,
    E_GUI_ID_R2_W,
    E_GUI_ID_TX_W,
    E_GUI_ID_END,
} id_range_t;

static inline force_start(int this_force, int cur_force)
{
    if (this_force == cur_force) {
        printf(C_GREEN);
    }
}

static inline force_end(int this_force, int cur_force)
{
    if (this_force == cur_force) {
        printf(C_NORMAL);
    }
}

void show_frame(struct olp param, int force)
{
    system("clear");
    // struct olp param;
    //   param.r1 = 1;
    //   param.t2 = 1;
    //   param.rx_p = -0.23;
    //   param.tx_p = -40.881;
    char strout[20];

    // snprintf(strout, 10, "%2f\n", -0.2);
    // printf("o : %s\r\n", strout);
    // snprintf(strout, 10, "%2f\n", -10.2);
    // printf("o : %s\r\n", strout);

    force_start(E_GUI_ID_MODE, force);
    if (param.mode == OLP_MODE_AUTO) {
        printf("Auto  ");
    }
    else {
        printf("Manual");
    }
    force_end(E_GUI_ID_MODE, force);

    force_start(E_GUI_ID_MS, force);
    if (param.route_bak == 1) {
        printf("   R2");
    }
    else {
        printf("   R1");
    }
    force_end(E_GUI_ID_MS, force);


    force_start(E_GUI_ID_AUTO, force);
    printf("   A:%4d", param.sw_auto_sec / 60);
    force_end(E_GUI_ID_AUTO, force);

    force_start(E_GUI_ID_MANUAL, force);
    printf("   M:%4d\r\n", param.sw_manual_sec / 60);
    force_end(E_GUI_ID_MANUAL, force);

    /*
     * R1 >----                (  0.00/  0.00)
     *          |----Rx
     * R2 x----                (  0.00/  0.00)
     */
    printf("R1 %c----          (%6.2f/", (param.route_bak == 1) ? 'x' : '>', param.r1_p);
    force_start(E_GUI_ID_R1_S, force);
    printf("%6.2f)", param.r1_s);
    force_end(E_GUI_ID_R1_S, force);

    force_start(E_GUI_ID_R1_W, force);
    printf("    %s\r\n", (param.r1_w == WAVE_1310) ? "1310" : "1550");
    force_end(E_GUI_ID_R1_W, force);

    printf("        |----Rx\r\n");

    printf("R2 %c----          (%6.2f/", (param.route_bak == 1) ? '>' : 'x', param.r2_p);
    force_start(E_GUI_ID_R2_S, force);
    printf("%6.2f)", param.r2_s);
    force_end(E_GUI_ID_R2_S, force);
    force_start(E_GUI_ID_R2_W, force);
    printf("    %s\r\n", (param.r2_w == WAVE_1310) ? "1310" : "1550");
    force_end(E_GUI_ID_R2_W, force);

    /*
     * Auto
     * T1 <----
     *         |----Tx         (  0.00/  0.00)
     * T2 x----
     */
    printf("T1 %c----\r\n", (param.route_bak == 1) ? 'x' : '<');
    printf("        |----Tx   (%6.2f/", param.tx_p);
    force_start(E_GUI_ID_TX_S, force);
    printf("%6.2f)", param.tx_s);
    force_end(E_GUI_ID_TX_S, force);

    force_start(E_GUI_ID_TX_W, force);
    printf("    %s\r\n", (param.tx_w == WAVE_1310) ? "1310" : "1550");
    force_end(E_GUI_ID_TX_W, force);
    printf("T2 %c----\r\n", (param.route_bak == 1) ? '<' : 'x');

    //////////////////////////////////////////////
    printf("e: 设置 n：下移 u：上移\r\n");
}
void test_serial(struct port_interface *port)
{
    char       strout[128];
    struct olp this_olp;
    // get_info(port);
    // get_info_query(port, &this_olp);
    test_rw(port, "<AD00_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD01_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD02_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD03_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD04_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD05_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD06_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD07_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD08_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD09_RESET>", strout, sizeof(strout), 1);

    test_rw(port, "<AD10_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD11_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD12_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD13_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD14_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD15_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD16_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD17_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD18_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD19_RESET>", strout, sizeof(strout), 1);


    test_rw(port, "<AD20_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD21_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD22_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD23_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD24_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD25_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD26_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD27_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD28_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD29_RESET>", strout, sizeof(strout), 1);


    test_rw(port, "<AD30_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD31_RESET>", strout, sizeof(strout), 1);
    test_rw(port, "<AD32_RESET>", strout, sizeof(strout), 1);
    // test_rw(port, "<AD01_INFO_?>", strout, sizeof(strout));
    // test_rw(port, "<AD01_MODULE_?>", strout, sizeof(strout));
    // test_rw(port, "<AD01_0_A_?>", strout, sizeof(strout));
    // test_rw(port, "<AD01_1_A_?>", strout, sizeof(strout));
    // test_rw(port, "<AD01_2_A_?>", strout, sizeof(strout));
    // test_rw(port, "<AD01_0_B_?>", strout, sizeof(strout));
    // test_rw(port, "<AD01_1_B_?>", strout, sizeof(strout));
    // test_rw(port, "<AD01_0_C_?>", strout, sizeof(strout));
    // test_rw(port, "<AD01_1_C_?>", strout, sizeof(strout));
    // test_rw(port, "<AD01_D_?>", strout, sizeof(strout));
    // test_rw(port, "<AD01_1_RX_W_1>", strout, sizeof(strout));
    // test_rw(port, "<AD01_0_TX_W_0>", strout, sizeof(strout));
    // test_rw(port, "<AD01_0_TX_W_1>", strout, sizeof(strout));
    // test_rw(port, "<AD01_1_TX_W_0>", strout, sizeof(strout));
    // test_rw(port, "<AD01_1_TX_W_1>", strout, sizeof(strout));
    // test_rw(port, "<AD01_1_M_0>", strout, sizeof(strout));
    // test_rw(port, "<AD01_1_M_1>", strout, sizeof(strout));
    // test_rw(port, "<AD01_1_S_1>", strout, sizeof(strout));
    // test_rw(port, "<AD01_1_S_2>", strout, sizeof(strout));
    test_rw(port, "<AD01_1_R_002>", strout, sizeof(strout), 1);
    sleep(1);

    // group
#if 0
	// test_rw(port, "<AD01_1_R1_P_-05.12>", strout, sizeof(strout), ENABLE_SHOW);
	// test_rw(port, "<AD01_1_R2_P_-32.34>", strout, sizeof(strout), ENABLE_SHOW);
	// test_rw(port, "<AD01_1_R3_P_-33.56>", strout, sizeof(strout), ENABLE_SHOW);
	test_rw(port, "<AD01_1_B_?>", strout, sizeof(strout));
#endif
    // test_rw(port, "<AD01_1_QUERY>", strout, sizeof(strout), ENABLE_SHOW);

    // test_rw(port, "<AD01_2_S_1>", strout, sizeof(strout));
    // test_rw(port, "<AD01_2_S_2>", strout, sizeof(strout));
    // test_rw(port, "<AD01_2_S_1>", strout, sizeof(strout));
    // test_rw(port, "<AD01_1_m_x>", strout, sizeof(strout));
    // char *cmd = "<AD01_RESE12321213T>\r";
    // char strout[1024];
    // int ret;

    // port->write(port, cmd, strlen(cmd));
    // ret = port->read(port, strout, sizeof(strout));

    // printf("ret %d\r\n", ret);
    // printf("s %s\r\n", strout);
    // strout[0] = '\0';
    // ret = port->read(port, strout, sizeof(strout));
    // printf("s %s\r\n", strout);
}


int input_number(char *prompt)
{
    int num;

    printf("%s", prompt);
    scanf("%d", &num);
    return num;
}

float input_float(char *prompt)
{
    float num;

    printf("%s", prompt);
    scanf("%f", &num);
    return num;
}


char wait_one_char()
{
    unsigned int   index = 0;
    struct termios oldattr, newattr;
    char           ch;

    tcgetattr(STDIN_FILENO, &oldattr);
    newattr = oldattr;
    newattr.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(STDIN_FILENO, TCSANOW, &newattr);
    ch = getchar();
    // while () {
    //     if (ch == 'q') {
    //         break;
    //     }
    //     switch (ch) {
    //     case 'n':
    //         index++;
    //         break;
    //     case 'p':
    //         index--;
    //         break;
    //     }
    //     printf("index %d\r\n", index);
    // }
    tcsetattr(STDIN_FILENO, TCSANOW, &oldattr);
    return ch;
}
void *thread_work(void *param)
{
    struct this_dlg *p = (struct this_dlg *)param;
    char             strout[128];
    // test_rw(p->port, "<AD01_1_SET1_-11.23_-13.45_0_1>", strout, sizeof(strout), 1);
    // test_rw(p->port, "<AD01_1_A_?>", strout, sizeof(strout), 1);
    while (1) {
        get_info_query(p->port, &p->m_olp);
        sleep(1);
        // test_rw(p->port, "<AD01_1_S_1>", strout, sizeof(strout), 1);
        // get_info_query(p->port, &p->m_olp);
        // sleep(4);
        // test_rw(p->port, "<AD01_1_S_2>", strout, sizeof(strout), 1);
        // get_info_query(p->port, &p->m_olp);
        // sleep(4);
    }
}

void test_ch(struct port_interface *port, int ch)
{
    char cmd[20];
    char strout[128];

    // snprintf(cmd, sizeof(cmd), "<AD01_1_S_%d>", ch);
    // printf("cmd : %s\r\n", cmd);
    // test_rw(port, cmd, strout, sizeof(strout), 1);
    while (1) {
        printf("准备切换 1\r\n");
        test_rw(port, "<AD01_1_S_1>", strout, sizeof(strout), 1);
        printf("完成切换 1\r\n");
        sleep(4);
        printf("准备切换 2\r\n");
        test_rw(port, "<AD01_1_S_2>", strout, sizeof(strout), 1);
        printf("完成切换 2\r\n");
        sleep(4);
    }
}
void edit_query_dlg(struct this_dlg *p)
{
    char cmd[30];
    char strout[128];
    char float_num[20];


    if (p->fource == E_GUI_ID_MODE) {
        test_rw(p->port, "<AD01_1_M_1>", strout, sizeof(strout), 1);
        // test_rw(p->port, "<AD17_1_M_1>", strout, sizeof(strout), 1);
    }
    else if (p->fource == E_GUI_ID_MS) {
        int ch;
        if (p->m_olp.route_bak == 1) {
            ch = 1;
        }
        else {
            ch = 2;
        }
        snprintf(cmd, sizeof(cmd), "<AD01_1_S_%d>", ch);
        // snprintf(cmd, sizeof(cmd), "<AD17_1_S_%d>", ch);
        test_rw(p->port, cmd, strout, sizeof(strout), 1);
        printf("正在切换\r\n");
    }

    else if (p->fource == E_GUI_ID_AUTO) {
        int min;
        min = input_number("自动回切延时(0:不回切; >0: 分): ");

        snprintf(cmd, sizeof(cmd), "<AD01_1_Q_%03d>", min);
        // snprintf(cmd, sizeof(cmd), "<AD17_1_Q_%03d>", min);
        test_rw(p->port, cmd, strout, sizeof(strout), 1);
    }
    else if (p->fource == E_GUI_ID_MANUAL) {
        int min;
        min = input_number("手动回切延时(0:不回切; >0: 分): ");
        snprintf(cmd, sizeof(cmd), "<AD01_1_R_%03d>", min);
        test_rw(p->port, cmd, strout, sizeof(strout), 1);
    }

    else if (p->fource == E_GUI_ID_R1_W || p->fource == E_GUI_ID_R2_W) {
        int wave;
        wave = input_number("工作波长(0:1310; 1: 1550): ");

        snprintf(cmd, sizeof(cmd), "<AD01_1_R%d_W_%d>", p->fource - E_GUI_ID_R1_W + 1, wave);
        test_rw(p->port, cmd, strout, sizeof(strout), 1);
    }
    else if (p->fource == E_GUI_ID_TX_W) {
        int wave;
        wave = input_number("工作波长(0:1310; 1: 1550): ");

        snprintf(cmd, sizeof(cmd), "<AD01_1_TX_W_%d>", wave);
        test_rw(p->port, cmd, strout, sizeof(strout), 1);
    }
    else if (p->fource == E_GUI_ID_R1_S ||
             p->fource == E_GUI_ID_R2_S ||
             p->fource == E_GUI_ID_TX_S) {
        float gain = input_float("功率:");
        float2str(gain, float_num, sizeof(float_num));
        snprintf(cmd, sizeof(cmd), "<AD01_1_R%d_P_%s>", p->fource - E_GUI_ID_R1_S + 1, float_num);
        // snprintf(cmd, sizeof(cmd), "<AD17_1_R%d_P_%s>", p->fource - E_GUI_ID_R1_S + 1, float_num);
        test_rw(p->port, cmd, strout, sizeof(strout), 1);
    }
    // else if (p->fource == E_GUI_ID_TX_S) {
    //     float gain = input_float("功率:");
    //     float2str(gain, float_num, sizeof(float_num));
    //     snprintf(cmd, sizeof(cmd), "<AD01_1_TX_P_%s>", float_num);
    //     test_rw(p->port, cmd, strout, sizeof(strout), 1);
    // }

    get_info_query(p->port, &p->m_olp);
}
void *thread_input(void *param)
{
    struct this_dlg *p = (struct this_dlg *)param;
    char             onechar;
    int              a;
    p->fource = 0;
    while (1) {
        onechar = wait_one_char();
        if (onechar == 'q') {
            break;
        }
        switch (onechar) {
        case 'n':
            p->fource++;
            break;
        case 'p':
            p->fource--;
            break;
        case 'e':
            p->en_draw = false;
            edit_query_dlg(p);
            // a = input_number("来一个吧: ");
            // printf("int a = %d\r\n", a);
            p->en_draw = true;
            break;
        }
        p->fource %= E_GUI_ID_END;
        pthread_cond_signal(&p->cond);
    }
}


pthread_cond_t s = PTHREAD_COND_INITIALIZER;
void           dialog(struct port_interface *port)
{
    id_range_t      fource = 0;
    struct this_dlg windlg;
    pthread_t       thread1, thread2;

    // windlg.mutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_init(&windlg.cond, NULL);
    pthread_mutex_init(&windlg.mutex, NULL);


    windlg.port = port;
    memset(&windlg.m_olp, 0, sizeof(struct olp));
    // char a = wait_one_char();
    // printf("a %x\r\n", a);
    pthread_create(&thread1, NULL, thread_work, &windlg);
    pthread_create(&thread2, NULL, thread_input, &windlg);

    // int  ch = input_number("切换通道(1:R1, 2:R2): ");
    // char cmd[20];
    // char strout[128];
    // snprintf(cmd, sizeof(cmd), "<AD01_1_S_%d>", ch);
    // test_rw(port, cmd, strout, sizeof(strout), 1);

    char            onechar;
    struct timespec ts;
    struct timeval  now;

    windlg.en_draw = true;
    while (1) {
        if (windlg.en_draw) {
            show_frame(windlg.m_olp, windlg.fource);
        }
        gettimeofday(&now, NULL);
        ts.tv_sec  = now.tv_sec + 1;
        ts.tv_nsec = now.tv_usec;

        pthread_mutex_lock(&windlg.mutex);
        pthread_cond_timedwait(&windlg.cond, &windlg.mutex, &ts);
        pthread_mutex_unlock(&windlg.mutex);
    }
    // force = GUI_ID_MODE;
}
void request_p(struct port_interface *port)
{
    struct olp tmp_olp;
    get_info_query(port, &tmp_olp);
    // get_info_query
    // show_frame(tmp_olp, 4);
    struct cJSON *pJsonRoot = cJSON_CreateObject();
    // json_ReadAdapter(pJsonRoot, (char*)"wan0");
    // cJSON_AddItemToObject(Json, "abc", "wml");
    char strout[16];
    snprintf(strout, sizeof(strout), "%6.2f", tmp_olp.r1_s);
    cJSON_AddStringToObject(pJsonRoot, "r1_s", strout);
    snprintf(strout, sizeof(strout), "%6.2f", tmp_olp.r1_p);
    cJSON_AddStringToObject(pJsonRoot, "r1_p", strout);

    snprintf(strout, sizeof(strout), "%6.2f", tmp_olp.r2_s);
    cJSON_AddStringToObject(pJsonRoot, "r2_s", strout);
    snprintf(strout, sizeof(strout), "%6.2f", tmp_olp.r2_p);
    cJSON_AddStringToObject(pJsonRoot, "r2_p", strout);

    snprintf(strout, sizeof(strout), "%6.2f", tmp_olp.tx_s);
    cJSON_AddStringToObject(pJsonRoot, "tx_s", strout);
    snprintf(strout, sizeof(strout), "%6.2f", tmp_olp.tx_p);
    cJSON_AddStringToObject(pJsonRoot, "tx_p", strout);


    snprintf(strout, sizeof(strout), "%d", tmp_olp.route_bak);
    cJSON_AddStringToObject(pJsonRoot, "route_bak", strout);

    snprintf(strout, sizeof(strout), "%s", (tmp_olp.r1_w == WAVE_1310) ? "1310" : "1550");
    cJSON_AddStringToObject(pJsonRoot, "r1_w", strout);
    snprintf(strout, sizeof(strout), "%s", (tmp_olp.r2_w == WAVE_1310) ? "1310" : "1550");
    cJSON_AddStringToObject(pJsonRoot, "r2_w", strout);
    snprintf(strout, sizeof(strout), "%s", (tmp_olp.tx_w == WAVE_1310) ? "1310" : "1550");
    cJSON_AddStringToObject(pJsonRoot, "tx_w", strout);

    snprintf(strout, sizeof(strout), "%d", tmp_olp.sw_manual_sec / 60);
    cJSON_AddStringToObject(pJsonRoot, "sw_manual_sec", strout);

    snprintf(strout, sizeof(strout), "%d", tmp_olp.sw_auto_sec / 60);
    cJSON_AddStringToObject(pJsonRoot, "sw_auto_sec", strout);

    snprintf(strout, sizeof(strout), "%d", tmp_olp.mode);
    cJSON_AddStringToObject(pJsonRoot, "mode", strout);
    


    //  r1_on, r2_on, tx_on;  // 相当与在主路还是在备路
    //  route_bak;

    //    sw_auto_sec;
    //    sw_manual_sec;

    // json_ReadAdapter(pJsonRoot, (char*)"lan0");
    printf("%s", cJSON_Print(pJsonRoot));
    // cJSON *pJsonInput = cJSON_Parse(pstrout);
}

struct webbox_arg
{
    cJSON *pJson;
};


struct box_method
{
    int (*fun)(struct webbox_arg *arg);
    char *method;
};

int raw_main(struct webbox_arg *arg)
{
    cJSON *pJsonInput = arg->pJson;
    struct cJSON *pJsonRoot = cJSON_CreateObject();

    char *pro_cmd = cJSON_GetObjectItem(pJsonInput, "cmd")->valuestring; // 暂时不用
    char strout[128];
    test_rw(g_port, pro_cmd, strout, sizeof(strout), DISABLE_SHOW);
    dprintf(g_dbgfd, "out: %s;\r\n\tin: %s\r\n", pro_cmd, strout);
    char *pstr = strstr(strout, ERR_FLAG);

    if (pstr == NULL) {  // SUCCESS
        cJSON_AddNumberToObject(pJsonRoot, "r", 100);
    }
    else {
        cJSON_AddNumberToObject(pJsonRoot, "r", 101);
    }

    cJSON_AddStringToObject(pJsonRoot, "msg", strout);
    printf("%s", cJSON_Print(pJsonRoot));
    return 0;
}
int brief_main(struct webbox_arg *arg)
{

}
int query_main(struct webbox_arg *arg)
{
    dprintf(g_dbgfd, "%s() %d\r\n", __FUNCTION__, __LINE__);
    request_p(g_port);
    return 0;
}

int set_gain_main(struct webbox_arg *arg)
{
    dprintf(g_dbgfd, "%s() %d\r\n", __FUNCTION__, __LINE__);
    struct cJSON *pJsonRoot = cJSON_CreateObject();
    char strout[128];

    //
    snprintf(strout, sizeof(strout), "%6.2f", 3.3);
    cJSON_AddStringToObject(pJsonRoot, "r1_s", strout);
    snprintf(strout, sizeof(strout), "%6.2f", 2.2);
    cJSON_AddStringToObject(pJsonRoot, "r1_p", strout);
    snprintf(strout, sizeof(strout), "%d", 444);
    cJSON_AddStringToObject(pJsonRoot, "sw_auto_sec", strout);

    char   pro_cmd[32];
    char   str_float_gain[20];
    cJSON *pJsonInput = arg->pJson;


    int   in_addr = cJSON_GetObjectItem(pJsonInput, "addr")->valueint; // 暂时不用
    int   in_link = cJSON_GetObjectItem(pJsonInput, "link")->valueint;
    int   in_rn   = cJSON_GetObjectItem(pJsonInput, "rn")->valueint;
    float in_gain = cJSON_GetObjectItem(pJsonInput, "gain")->valuedouble;
    
    float2str(in_gain, str_float_gain, sizeof(str_float_gain));
    snprintf(pro_cmd, sizeof(pro_cmd), "<AD01_%d_R%d_P_%s>", in_link, in_rn, str_float_gain);

    memset(strout, sizeof(strout), 0);
    dprintf(g_dbgfd, "input %s\r\n", cJSON_Print(pJsonInput));
    test_rw(g_port, pro_cmd, strout, sizeof(strout), DISABLE_SHOW);
    dprintf(g_dbgfd, "out: %s;\r\n\tin: %s\r\n", pro_cmd, strout);


    char *pstr = strstr(strout, ERR_FLAG);

    if (pstr == NULL) {  // SUCCESS
        cJSON_AddNumberToObject(pJsonRoot, "r", 100);
    }
    else {
        cJSON_AddNumberToObject(pJsonRoot, "r", 101);
    }

    cJSON_AddStringToObject(pJsonRoot, "msg", strout);
    printf("%s", cJSON_Print(pJsonRoot));
    return 0;
}
int set_wave_main(struct webbox_arg *arg)
{
    dprintf(g_dbgfd, "%s() %d\r\n", __FUNCTION__, __LINE__);
    struct cJSON *pJsonRoot = cJSON_CreateObject();
    char strout[128];

    //
    snprintf(strout, sizeof(strout), "%6.2f", 3.3);
    cJSON_AddStringToObject(pJsonRoot, "r1_s", strout);
    snprintf(strout, sizeof(strout), "%6.2f", 2.2);
    cJSON_AddStringToObject(pJsonRoot, "r1_p", strout);
    snprintf(strout, sizeof(strout), "%d", 444);
    cJSON_AddStringToObject(pJsonRoot, "sw_auto_sec", strout);

    char   pro_cmd[32];
    char   str_float_gain[20];
    cJSON *pJsonInput = arg->pJson;


    int   in_addr = cJSON_GetObjectItem(pJsonInput, "addr")->valueint; // 暂时不用
    int   in_link = cJSON_GetObjectItem(pJsonInput, "link")->valueint;
    int   in_rn   = cJSON_GetObjectItem(pJsonInput, "rn")->valueint;
    int   in_wave = cJSON_GetObjectItem(pJsonInput, "wave")->valueint;
    
    if (in_rn != 3) {
        snprintf(pro_cmd, sizeof(pro_cmd), "<AD01_%d_R%d_W_%d>", in_link, in_rn, in_wave);
    }
    else {
        snprintf(pro_cmd, sizeof(pro_cmd), "<AD01_%d_TX_W_%d>", in_link, in_wave);
    }

    memset(strout, sizeof(strout), 0);
    dprintf(g_dbgfd, "input %s\r\n", cJSON_Print(pJsonInput));
    test_rw(g_port, pro_cmd, strout, sizeof(strout), DISABLE_SHOW);
    dprintf(g_dbgfd, "out: %s;\r\n\tin: %s\r\n", pro_cmd, strout);


    char *pstr = strstr(strout, ERR_FLAG);

    if (pstr == NULL) {  // SUCCESS
        cJSON_AddNumberToObject(pJsonRoot, "r", 100);
    }
    else {
        cJSON_AddNumberToObject(pJsonRoot, "r", 101);
    }

    cJSON_AddStringToObject(pJsonRoot, "msg", strout);
    printf("%s", cJSON_Print(pJsonRoot));
    return 0;
}

#define ADD    1
#define REMOVE 0
int run_stop_main(struct webbox_arg *arg)
{
    dprintf(g_dbgfd, "run_stop_main\r\n");
    // struct cJSON *pJsonRoot = cJSON_CreateObject();
    cJSON *pJsonInput = arg->pJson;
    int   dowhat = cJSON_GetObjectItem(pJsonInput, "do")->valueint; // 暂时不用
    if (dowhat == ADD) {
        system("echo > /tmp/stop_olp");
    }
    else {
        system("rm /tmp/stop_olp");
    }
    return 0;
}


struct box_method titem[] = {
    { raw_main},        // 0
    { brief_main },     // 1
    { query_main },     // 2
    { set_gain_main },  // 3
    { set_wave_main },     // 4
    { run_stop_main },     // 5
    { brief_main },     // 6
    { brief_main },     // 7
    { brief_main },     

};

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdarg.h>


void log_init()
{
    // TODO 如果没有fifo则创建
    g_dbgfd = open("/tmp/outfifo", O_RDWR);
}


// void log(const char *fmt, ...)
// {
//     // char strout[444];
//     // write(g_dbgfd, "\r\n1243", 4);


//     // va_list args;
//     // int     r;

//     // va_start(args, fmt);
//     // r = dprintf(g_dbgfd, fmt, args);
//     // va_end(args);

//     // printf("r %d\r\n", r);
//     // return r;
// }

void fun_getcontent(struct port_interface *port)
{

    g_port = port;


    char              strout[1024];
    char             *pstrout = strout;
    unsigned int      len;
    struct webbox_arg arg;
    char             *p = getenv("CONTENT_LENGTH");

    dprintf(g_dbgfd, "p12 = %s\r\n", p);
    dprintf(g_dbgfd, "sdfdasf 2231 %d %d %d\r\n", 1, 2, 3);

    if (p) {
        len = atoi(p);
        len += 1;
        if (len > sizeof(strout) / sizeof(strout[0])) {
            pstrout = (char *)malloc(len);
            fgets(pstrout, len, stdin);
        }
        else {
            fgets(strout, len, stdin);
        }
        dprintf(g_dbgfd, "in %s\r\n", pstrout);
        cJSON *pJsonInput = cJSON_Parse(pstrout);


        arg.pJson = pJsonInput;
        titem[cJSON_GetObjectItem(pJsonInput, "m")->valueint].fun(&arg);
        return 0;
    }
}
int main(int argc, char *argv[])
{
    struct port_interface *port = NULL;
    int                    ret  = 1;
    stm32_err_t            s_err;
    parser_err_t           perr;
    FILE                  *diag = stdout;

    //	fprintf(diag, "stm32flash " VERSION "\n\n");
    //	fprintf(diag, "http://stm32flash.googlecode.com/\n\n");
#if 0
    if (parse_options(argc, argv) != 0)
        goto close;
    // printf("fname %s\r\n", filename[0]);
    if (rd && filename[0] == '-') {
        diag = stderr;
    }

    if (wr) {
        /* first try hex */
        if (!force_binary) {
            parser = &PARSER_HEX;
            p_st   = parser->init();
            if (!p_st) {
                fprintf(stderr, "%s Parser failed to initialize\n", parser->name);
                goto close;
            }
        }

        if (force_binary ||
            (perr = parser->open(p_st, filename, 0)) != PARSER_ERR_OK) {
            if (force_binary || perr == PARSER_ERR_INVALID_FILE) {
                if (!force_binary) {
                    parser->close(p_st);
                    p_st = NULL;
                }

                /* now try binary */
                parser = &PARSER_BINARY;
                p_st   = parser->init();
                if (!p_st) {
                    fprintf(stderr, "%s Parser failed to initialize\n", parser->name);
                    goto close;
                }
                perr = parser->open(p_st, filename, 0);
            }

            /* if still have an error, fail */
            if (perr != PARSER_ERR_OK) {
                fprintf(stderr, "%s ERROR: %s\n", parser->name, parser_errstr(perr));
                if (perr == PARSER_ERR_SYSTEM)
                    perror(filename);
                goto close;
            }
        }

        fprintf(diag, "Using Parser : %s\n", parser->name);
    }
    else {
        parser = &PARSER_BINARY;
        p_st   = parser->init();
        if (!p_st) {
            fprintf(stderr, "%s Parser failed to initialize\n", parser->name);
            goto close;
        }
    }
#endif
    // port_opts.device = argv[1];
    if (port_open(&port_opts, &port) != PORT_ERR_OK) {
        fprintf(stderr, "Failed to open port: %s\n", port_opts.device);
        goto close;
    }
    struct olp tmp_olp;

    log_init();
    // test_serial(port);
    printf("Content-type:text/html\n\n");
    fun_getcontent(port);
    // request_p(port);
    // get_info_query(port, &tmp_olp);
    // get_info_query
    // // show_frame(tmp_olp, 4);
    // // cJSON *pJsonInput = cJSON_Parse(pstrout);
    exit(0);
    fprintf(diag, "Interface %s: %s\n", port->name, port->get_cfg_str(port));
    if (init_flag && init_bl_entry(port, gpio_seq) == 0)
        goto close;

    // exit(0);
    //   g_param.rx_p = 2;
    //   g_param.tx_p = 2;
    // input_number();
    // pthread_mutex_init(&port->mutex, NULL);
    // test_ch(port, 0);
    dialog(port);
    exit(0);

close:
    if (stm && exec_flag && ret == 0) {
        if (execute == 0)
            execute = stm->dev->fl_start;

        fprintf(diag, "\nStarting execution at address 0x%08x... ", execute);
        fflush(diag);
        if (stm32_go(stm, execute) == STM32_ERR_OK) {
            reset_flag = 0;
            fprintf(diag, "done.\n");
        }
        else
            fprintf(diag, "failed.\n");
    }

    if (stm && reset_flag) {
        fprintf(diag, "\nResetting device... ");
        fflush(diag);
        if (init_bl_exit(stm, port, gpio_seq))
            fprintf(diag, "done.\n");
        else
            fprintf(diag, "failed.\n");
    }

    if (p_st)
        parser->close(p_st);
    if (stm)
        stm32_close(stm);
    if (port)
        port->close(port);

    fprintf(diag, "\n");
    return ret;
}

int parse_options(int argc, char *argv[])
{
    int   c;
    char *pLen;

    while ((c = getopt(argc, argv, "a:b:m:r:w:e:vn:g:jkfcChuos:S:F:i:R")) != -1) {
        switch (c) {
        case 'a':
            port_opts.bus_addr = strtoul(optarg, NULL, 0);
            break;

        case 'b':
            port_opts.baudRate = serial_get_baud(strtoul(optarg, NULL, 0));
            if (port_opts.baudRate == SERIAL_BAUD_INVALID) {
                serial_baud_t baudrate;
                fprintf(stderr, "Invalid baud rate, valid options are:\n");
                for (baudrate = SERIAL_BAUD_1200; baudrate != SERIAL_BAUD_INVALID;
                     ++baudrate)
                    fprintf(stderr, " %d\n", serial_get_baud_int(baudrate));
                return 1;
            }
            break;

        case 'm':
            if (strlen(optarg) != 3 ||
                serial_get_bits(optarg) == SERIAL_BITS_INVALID ||
                serial_get_parity(optarg) == SERIAL_PARITY_INVALID ||
                serial_get_stopbit(optarg) == SERIAL_STOPBIT_INVALID) {
                fprintf(stderr, "Invalid serial mode\n");
                return 1;
            }
            port_opts.serial_mode = optarg;
            break;

        case 'r':
        case 'w':
            rd = rd || c == 'r';
            wr = wr || c == 'w';
            if (rd && wr) {
                fprintf(
                        stderr,
                        "ERROR: Invalid options, can't read & write at the same time\n");
                return 1;
            }
            filename = optarg;
            if (filename[0] == '-') {
                force_binary = 1;
            }
            break;
        case 'e':
            if (readwrite_len || start_addr) {
                fprintf(stderr, "ERROR: Invalid options, can't specify start page / "
                                "num pages and start address/length\n");
                return 1;
            }
            npages = strtoul(optarg, NULL, 0);
            if (npages > 0xFF || npages < 0) {
                fprintf(stderr,
                        "ERROR: You need to specify a page count between 0 and 255");
                return 1;
            }
            if (!npages)
                no_erase = 1;
            break;
        case 'u':
            wu = 1;
            if (rd || wr) {
                fprintf(stderr, "ERROR: Invalid options, can't write unprotect and "
                                "read/write at the same time\n");
                return 1;
            }
            break;

        case 'j':
            rp = 1;
            if (rd || wr) {
                fprintf(stderr, "ERROR: Invalid options, can't read protect and "
                                "read/write at the same time\n");
                return 1;
            }
            break;

        case 'k':
            ur = 1;
            if (rd || wr) {
                fprintf(stderr, "ERROR: Invalid options, can't read unprotect and "
                                "read/write at the same time\n");
                return 1;
            }
            break;

        case 'o':
            eraseOnly = 1;
            if (rd || wr) {
                fprintf(stderr, "ERROR: Invalid options, can't erase-only and "
                                "read/write at the same time\n");
                return 1;
            }
            break;

        case 'v':
            verify = 1;
            break;

        case 'n':
            retry = strtoul(optarg, NULL, 0);
            break;

        case 'g':
            exec_flag = 1;
            execute   = strtoul(optarg, NULL, 0);
            if (execute % 4 != 0) {
                fprintf(stderr, "ERROR: Execution address must be word-aligned\n");
                return 1;
            }
            break;
        case 's':
            if (readwrite_len || start_addr) {
                fprintf(stderr, "ERROR: Invalid options, can't specify start page / "
                                "num pages and start address/length\n");
                return 1;
            }
            spage = strtoul(optarg, NULL, 0);
            break;
        case 'S':
            if (spage || npages) {
                fprintf(stderr, "ERROR: Invalid options, can't specify start page / "
                                "num pages and start address/length\n");
                return 1;
            }
            else {
                start_addr = strtoul(optarg, &pLen, 0);
                if (*pLen == ':') {
                    pLen++;
                    readwrite_len = strtoul(pLen, NULL, 0);
                    if (readwrite_len == 0) {
                        fprintf(stderr,
                                "ERROR: Invalid options, can't specify zero length\n");
                        return 1;
                    }
                }
            }
            break;
        case 'F':
            port_opts.rx_frame_max = strtoul(optarg, &pLen, 0);
            if (*pLen == ':') {
                pLen++;
                port_opts.tx_frame_max = strtoul(pLen, NULL, 0);
            }
            if (port_opts.rx_frame_max < 0 || port_opts.tx_frame_max < 0) {
                fprintf(stderr, "ERROR: Invalid negative value for option -F\n");
                return 1;
            }
            if (port_opts.rx_frame_max == 0)
                port_opts.rx_frame_max = STM32_MAX_RX_FRAME;
            if (port_opts.tx_frame_max == 0)
                port_opts.tx_frame_max = STM32_MAX_TX_FRAME;
            if (port_opts.rx_frame_max < 20 || port_opts.tx_frame_max < 5) {
                fprintf(stderr, "ERROR: current code cannot work with small frames.\n");
                fprintf(stderr, "min(RX) = 20, min(TX) = 5\n");
                return 1;
            }
            if (port_opts.rx_frame_max > STM32_MAX_RX_FRAME) {
                fprintf(stderr, "WARNING: Ignore RX length in option -F\n");
                port_opts.rx_frame_max = STM32_MAX_RX_FRAME;
            }
            if (port_opts.tx_frame_max > STM32_MAX_TX_FRAME) {
                fprintf(stderr, "WARNING: Ignore TX length in option -F\n");
                port_opts.tx_frame_max = STM32_MAX_TX_FRAME;
            }
            break;
        case 'f':
            force_binary = 1;
            break;

        case 'c':
            init_flag = 0;
            break;

        case 'h':
            show_help(argv[0]);
            exit(0);

        case 'i':
            gpio_seq = optarg;
            break;

        case 'R':
            reset_flag = 1;
            break;

        case 'C':
            crc = 1;
            break;
        }
    }

    for (c = optind; c < argc; ++c) {
        if (port_opts.device) {
            fprintf(stderr, "ERROR: Invalid parameter specified\n");
            show_help(argv[0]);
            return 1;
        }
        port_opts.device = argv[c];
    }

    if (port_opts.device == NULL) {
        fprintf(stderr, "ERROR: Device not specified\n");
        show_help(argv[0]);
        return 1;
    }

    if (!wr && verify) {
        fprintf(stderr, "ERROR: Invalid usage, -v is only valid when writing\n");
        show_help(argv[0]);
        return 1;
    }

    return 0;
}

void show_help(char *name)
{
    fprintf(
            stderr,
            "Usage: %s [-bvngfhc] [-[rw] filename] [tty_device | i2c_device]\n"
            "	-a bus_address	Bus address (e.g. for I2C port)\n"
            "	-b rate		Baud rate (default 57600)\n"
            "	-m mode		Serial port mode (default 8e1)\n"
            "	-r filename	Read flash to file (or - stdout)\n"
            "	-w filename	Write flash from file (or - stdout)\n"
            "	-C		Compute CRC of flash content\n"
            "	-u		Disable the flash write-protection\n"
            "	-j		Enable the flash read-protection\n"
            "	-k		Disable the flash read-protection\n"
            "	-o		Erase only\n"
            "	-e n		Only erase n pages before writing the flash\n"
            "	-v		Verify writes\n"
            "	-n count	Retry failed writes up to count times (default 10)\n"
            "	-g address	Start execution at specified address (0 = flash "
            "start)\n"
            "	-S address[:length]	Specify start address and optionally length "
            "for\n"
            "	                   	read/write/erase operations\n"
            "	-F RX_length[:TX_length]  Specify the max length of RX and TX frame\n"
            "	-s start_page	Flash at specified page (0 = flash start)\n"
            "	-f		Force binary parser\n"
            "	-h		Show this help\n"
            "	-c		Resume the connection (don't send initial INIT)\n"
            "			*Baud rate must be kept the same as the first init*\n"
            "			This is useful if the reset fails\n"
            "	-i GPIO_string	GPIO sequence to enter/exit bootloader mode\n"
            "			GPIO_string=[entry_seq][:[exit_seq]]\n"
            "			sequence=[-]n[,sequence]\n"
            "	-R		Reset device at exit.\n"
            "\n"
            "Examples:\n"
            "	Get device information:\n"
            "		%s /dev/ttyS0\n"
            "	  or:\n"
            "		%s /dev/i2c-0\n"
            "\n"
            "	Write with verify and then start execution:\n"
            "		%s -w filename -v -g 0x0 /dev/ttyS0\n"
            "\n"
            "	Read flash to file:\n"
            "		%s -r filename /dev/ttyS0\n"
            "\n"
            "	Read 100 bytes of flash from 0x1000 to stdout:\n"
            "		%s -r - -S 0x1000:100 /dev/ttyS0\n"
            "\n"
            "	Start execution:\n"
            "		%s -g 0x0 /dev/ttyS0\n"
            "\n"
            "	GPIO sequence:\n"
            "	- entry sequence: GPIO_3=low, GPIO_2=low, GPIO_2=high\n"
            "	- exit sequence: GPIO_3=high, GPIO_2=low, GPIO_2=high\n"
            "		%s -i -3,-2,2:3,-2,2 /dev/ttyS0\n",
            name,
            name,
            name,
            name,
            name,
            name,
            name,
            name);
}
